bitkeeper revision 1.1254 (42405db8CeBSiHgkIfnk7WeA9Pvjmw)
authormafetter@fleming.research <mafetter@fleming.research>
Tue, 22 Mar 2005 18:02:32 +0000 (18:02 +0000)
committermafetter@fleming.research <mafetter@fleming.research>
Tue, 22 Mar 2005 18:02:32 +0000 (18:02 +0000)
HL2's are now filled in on demand, rather than by doing the entire thing
on creation.  Also fixed a bug in hl2 ref counting.  hl2 entries don't
take a writable ref to the guest pages, as they are xen mappings, not
guest mappings.  Also fixed a tlb flushing bug with hl2 entries.

Bug fix for shadow table ref counting.  CR3's shadow table could, in theory,
get released while it's still pointing at it.  Fixed.

Bug fix for shadow code with tlb flushes from hypervisor calls.

Signed-off-by: michael.fetterman@cl.cam.ac.uk
xen/arch/x86/audit.c
xen/arch/x86/mm.c
xen/arch/x86/shadow.c
xen/include/asm-x86/domain.h
xen/include/asm-x86/shadow.h
xen/include/xen/perfc_defn.h

index 5aaebd936d4398c1584849cb46d1ff375c08be32..97a7baf8bd166d9766c1138f592ccf8f82025371 100644 (file)
@@ -411,6 +411,8 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy)
                     if ( pagetable_val(ed->arch.shadow_table) )
                         adjust(&frame_table[pagetable_val(ed->arch.shadow_table)
                                             >> PAGE_SHIFT], 0);
+                    if ( ed->arch.monitor_shadow_ref )
+                        adjust(&frame_table[ed->arch.monitor_shadow_ref], 0);
                 }
             }
     }
index 3048613abed6f1e3a72089ceaf65d305738e01b2..6af85c0602e0da3e6c8b977a7cbb6365c5fb83da 100644 (file)
@@ -1271,6 +1271,18 @@ int new_guest_cr3(unsigned long mfn)
             put_page(&frame_table[old_base_mfn]);
         else
             put_page_and_type(&frame_table[old_base_mfn]);
+
+        // CR3 holds its own ref to its shadow...
+        //
+        if ( shadow_mode_enabled(d) )
+        {
+            if ( ed->arch.monitor_shadow_ref )
+                put_shadow_ref(ed->arch.monitor_shadow_ref);
+            ed->arch.monitor_shadow_ref =
+                pagetable_val(ed->arch.monitor_table) >> PAGE_SHIFT;
+            ASSERT(page_get_owner(&frame_table[ed->arch.monitor_shadow_ref]) == NULL);
+            get_shadow_ref(ed->arch.monitor_shadow_ref);
+        }
     }
     else
     {
@@ -1386,9 +1398,9 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         break;
     
     case MMUEXT_INVLPG:
-        __flush_tlb_one(ptr);
         if ( shadow_mode_enabled(d) )
             shadow_invlpg(ed, ptr);
+        __flush_tlb_one(ptr);
         break;
 
     case MMUEXT_FLUSH_CACHE:
@@ -1940,9 +1952,9 @@ int do_mmu_update(
 
     if ( deferred_ops & DOP_FLUSH_TLB )
     {
-        local_flush_tlb();
         if ( shadow_mode_enabled(d) )
             shadow_sync_all(d);
+        local_flush_tlb();
     }
         
     if ( deferred_ops & DOP_RELOAD_LDT )
@@ -2072,15 +2084,15 @@ int do_update_va_mapping(unsigned long va,
     if ( unlikely(deferred_ops & DOP_FLUSH_TLB) || 
          unlikely(flags & UVMF_FLUSH_TLB) )
     {
-        local_flush_tlb();
         if ( unlikely(shadow_mode_enabled(d)) )
             shadow_sync_all(d);
+        local_flush_tlb();
     }
     else if ( unlikely(flags & UVMF_INVLPG) )
     {
-        __flush_tlb_one(va);
         if ( unlikely(shadow_mode_enabled(d)) )
             shadow_invlpg(current, va);
+        __flush_tlb_one(va);
     }
 
     if ( unlikely(deferred_ops & DOP_RELOAD_LDT) )
index adffaec447fcae90d6db4d609e325253d5946966..8208382334ec97a85be18273f66109c64bb8c8e2 100644 (file)
@@ -62,10 +62,14 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn,
     if ( unlikely(page_is_page_table(page)) )
         return 1;
 
-    FSH_LOG("shadow_promote gpfn=%p gmfn=%p nt=%p", gpfn, gmfn, new_type);
+    FSH_LOG("%s: gpfn=%p gmfn=%p nt=%p", __func__, gpfn, gmfn, new_type);
 
     if ( !shadow_remove_all_write_access(d, gpfn, gmfn) )
+    {
+        FSH_LOG("%s: couldn't find/remove all write accesses, gpfn=%p gmfn=%p\n",
+                __func__, gpfn, gmfn);
         return 0;
+    }
 
     // To convert this page to use as a page table, the writable count
     // should now be zero.  Test this by grabbing the page as an page table,
@@ -1236,8 +1240,7 @@ shadow_hl2_table(struct domain *d, unsigned long gpfn, unsigned long gmfn,
 {
     unsigned long hl2mfn;
     l1_pgentry_t *hl2;
-    l2_pgentry_t *gl2;
-    int i, limit;
+    int limit;
 
     ASSERT(PGT_base_page_table == PGT_l2_page_table);
 
@@ -1249,7 +1252,6 @@ shadow_hl2_table(struct domain *d, unsigned long gpfn, unsigned long gmfn,
 
     perfc_incrc(shadow_hl2_table_count);
 
-    gl2 = map_domain_mem(gmfn << PAGE_SHIFT);
     hl2 = map_domain_mem(hl2mfn << PAGE_SHIFT);
 
     if ( shadow_mode_external(d) )
@@ -1257,19 +1259,7 @@ shadow_hl2_table(struct domain *d, unsigned long gpfn, unsigned long gmfn,
     else
         limit = DOMAIN_ENTRIES_PER_L2_PAGETABLE;
 
-    for ( i = 0; i < limit; i++ )
-    {
-        unsigned long gl2e = l2_pgentry_val(gl2[i]);
-        unsigned long hl2e;
-
-        hl2e_propagate_from_guest(d, gl2e, &hl2e);
-
-        if ( (hl2e & _PAGE_PRESENT) &&
-             !get_page(pfn_to_page(hl2e >> PAGE_SHIFT), d) )
-            hl2e = 0;
-
-        hl2[i] = mk_l1_pgentry(hl2e);
-    }
+    memset(hl2, 0, limit * sizeof(l1_pgentry_t));
 
     if ( !shadow_mode_external(d) )
     {
@@ -1287,7 +1277,6 @@ shadow_hl2_table(struct domain *d, unsigned long gpfn, unsigned long gmfn,
     }
 
     unmap_domain_mem(hl2);
-    unmap_domain_mem(gl2);
 
     return hl2mfn;
 }
index ea11b9ff7182235a9da9abf0f3a01015b5c9e42e..47d1b678f6cd5761edbe69ed58a813774d46924a 100644 (file)
@@ -122,6 +122,8 @@ struct arch_exec_domain
     l2_pgentry_t *monitor_vtable;              /* virtual address of monitor_table */
     l1_pgentry_t *hl2_vtable;                  /* virtual address of hl2_table */
 
+    unsigned long monitor_shadow_ref;
+
     /* Virtual CR2 value. Can be read/written by guest. */
     unsigned long guest_cr2;
 
index 5f17c29df473c333d7f14e03666ada07fcac5180..dd4ae21034c3f637af865ac9e674f48a785fec31 100644 (file)
@@ -67,6 +67,7 @@ extern int set_p2m_entry(
 
 static inline unsigned long __shadow_status(
     struct domain *d, unsigned long gpfn, unsigned long stype);
+static inline void update_hl2e(struct exec_domain *ed, unsigned long va);
 
 extern void vmx_shadow_clear_state(struct domain *);
 
@@ -121,6 +122,11 @@ __shadow_sync_va(struct exec_domain *ed, unsigned long va)
         //
         __shadow_sync_all(ed->domain);
     }
+
+    // Also make sure the HL2 is up-to-date for this address.
+    //
+    if ( unlikely(shadow_mode_translate(ed->domain)) )
+        update_hl2e(ed, va);
 }
 
 static void inline
@@ -314,34 +320,58 @@ static inline void
 __guest_set_l2e(
     struct exec_domain *ed, unsigned long va, unsigned long value)
 {
+    ed->arch.guest_vtable[l2_table_offset(va)] = mk_l2_pgentry(value);
+
     if ( unlikely(shadow_mode_translate(ed->domain)) )
-    {
-        unsigned long mfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
-        unsigned long old_hl2e =
-            l1_pgentry_val(ed->arch.hl2_vtable[l2_table_offset(va)]);
-        unsigned long new_hl2e =
-            (VALID_MFN(mfn) ? ((mfn << PAGE_SHIFT) | __PAGE_HYPERVISOR) : 0);
+        update_hl2e(ed, va);
+}
 
-        // only do the ref counting if something important changed.
-        //
-        if ( (old_hl2e ^ new_hl2e) & (PAGE_MASK | _PAGE_PRESENT) )
+static inline void
+update_hl2e(struct exec_domain *ed, unsigned long va)
+{
+    int index = l2_table_offset(va);
+    unsigned long gl2e = l2_pgentry_val(ed->arch.guest_vtable[index]);
+    unsigned long mfn;
+    unsigned long old_hl2e, new_hl2e;
+    int need_flush = 0;
+
+    ASSERT(shadow_mode_translate(ed->domain));
+
+    old_hl2e = l1_pgentry_val(ed->arch.hl2_vtable[index]);
+
+    if ( (gl2e & _PAGE_PRESENT) &&
+         VALID_MFN(mfn = phys_to_machine_mapping(gl2e >> PAGE_SHIFT)) )
+        new_hl2e = (mfn << PAGE_SHIFT) | __PAGE_HYPERVISOR;
+    else
+        new_hl2e = 0;
+
+    // only do the ref counting if something important changed.
+    //
+    if ( (old_hl2e ^ new_hl2e) & (PAGE_MASK | _PAGE_PRESENT) )
+    {
+        if ( (new_hl2e & _PAGE_PRESENT) &&
+             !get_page(pfn_to_page(new_hl2e >> PAGE_SHIFT), ed->domain) )
+            new_hl2e = 0;
+        if ( old_hl2e & _PAGE_PRESENT )
         {
-            if ( (new_hl2e & _PAGE_PRESENT) &&
-                 !shadow_get_page_from_l1e(mk_l1_pgentry(new_hl2e), ed->domain) )
-                new_hl2e = 0;
-            if ( old_hl2e & _PAGE_PRESENT )
-                put_page_from_l1e(mk_l1_pgentry(old_hl2e), ed->domain);
+            put_page(pfn_to_page(old_hl2e >> PAGE_SHIFT));
+            need_flush = 1;
         }
-
-        ed->arch.hl2_vtable[l2_table_offset(va)] = mk_l1_pgentry(new_hl2e);
     }
 
-    ed->arch.guest_vtable[l2_table_offset(va)] = mk_l2_pgentry(value);
+    ed->arch.hl2_vtable[l2_table_offset(va)] = mk_l1_pgentry(new_hl2e);
+
+    if ( need_flush )
+    {
+        perfc_incrc(update_hl2e_invlpg);
+        __flush_tlb_one(&linear_pg_table[l1_linear_offset(va)]);
+    }
 }
 
+
 /************************************************************************/
 
-//#define MFN3_TO_WATCH 0x1ff6e
+//#define MFN3_TO_WATCH 0x8575
 #ifdef MFN3_TO_WATCH
 #define get_shadow_ref(__s) (                                                 \
 {                                                                             \
index 3544c82e11d24adf882af73ab631c00bbfe2be31..db05fa2f25f40f8397f909089666fcb2971e0ba7 100644 (file)
@@ -97,3 +97,4 @@ PERFCOUNTER_CPU(remove_write_predicted,            "remove_write predict hit&exi
 PERFCOUNTER_CPU(remove_write_bad_prediction,       "remove_write bad prediction")
 PERFCOUNTER_CPU(write_fault_bail,                  "sf bailed due to write_fault")
 PERFCOUNTER_CPU(read_fault_bail,                   "sf bailed due to read_fault")
+PERFCOUNTER_CPU(update_hl2e_invlpg,                 "update_hl2e calls invlpg")